package com.gufe.controller.webSocket;

import com.gufe.controller.webSocket.Handler.HanderHeartBeat;
import com.gufe.controller.webSocket.Handler.HandlerWebSocket;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.handler.codec.http.HttpObjectAggregator;
import io.netty.handler.codec.http.HttpServerCodec;
import io.netty.handler.codec.http.websocketx.WebSocketServerProtocolHandler;
import io.netty.handler.timeout.IdleStateHandler;
import io.netty.util.AttributeKey;
import jakarta.annotation.PreDestroy;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;

import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
@EnableAsync
public class WebSocketStarter {

    private final EventLoopGroup bossGroup = new NioEventLoopGroup();
    private final EventLoopGroup workerGroup = new NioEventLoopGroup();

    //定义userId与channel映射关系
    public static final ConcurrentHashMap<String, Channel> userChannels = new ConcurrentHashMap<>();
    public static final AttributeKey<String> USER_ID_KEY = AttributeKey.valueOf("userId");

    @Value("${server.webSocket.port}")
    private Integer port; // 启动端口号

    @Resource
    private HanderHeartBeat handerHeartBeat;
    @Resource
    private HandlerWebSocket handlerWebSocket;

    //spring启动时自启动
    @Async
    public void startNetty()  {
        ServerBootstrap bootstrap = new ServerBootstrap();
        bootstrap.group(bossGroup, workerGroup);
        bootstrap.channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<Channel>() {
                    @Override
                    protected void initChannel(Channel channel) throws Exception {
                        ChannelPipeline pipeline = channel.pipeline();
                        //设置处理器对http协议的支持，使用http的解码器和编码器
                        pipeline.addLast(new HttpServerCodec());
                        //聚合解码，保证接收的http请求的完整性
                        pipeline.addLast(new HttpObjectAggregator(64 * 1024));

                        //读超时readerIdleTime,写超时writerIdleTime,所有类型的超时allIdleTime,单位TimeUnit unit
                        //心跳机制，设置客户端心跳条件超时为反应就会断掉连接
                        pipeline.addLast(new IdleStateHandler(20, 0, 0, TimeUnit.MINUTES));
                        pipeline.addLast(handerHeartBeat);//导入心跳定义机制
                        //将http协升级为ws协议，对websocket支持
                        pipeline.addLast(new WebSocketServerProtocolHandler(
                                "/ws",       // 路径
                                null,        // 子协议（不限制）
                                true,        // 允许扩展
                                64 * 1024,       // 最大帧负载长度（字节）
                                false,       // 不允许未掩码帧
                                true,       // 路径严格匹配
                                20000L        // 握手超时时间（20 秒）
                        ));
                        pipeline.addLast(handlerWebSocket);//导入自己定义的处理器
                    }
                });
        // 异步绑定，不阻塞主线程
        ChannelFuture channelFuture = bootstrap.bind(port);
        channelFuture.addListener(future -> {
            if (future.isSuccess()) {
                log.info("WebSocket成功启动于{}端口", port);
            } else {
                log.error("WebSocket启动失败", future.cause());
            }
        });
        channelFuture.channel().closeFuture().syncUninterruptibly();
    }

    //@PreDestroy 注解来确保在 Spring Boot 应用关闭时，Netty 的资源能够被正确释放。
    @PreDestroy
    public void stopNetty() {
        bossGroup.shutdownGracefully();
        workerGroup.shutdownGracefully();
        log.info("WebSocket服务器已关闭");
    }
}
